import { AppContext } from '@/store/index.context';
import { RoundInfo } from '@/types/game';
import React, { useCallback, useContext, useMemo } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useMount } from 'ahooks';
import SelectRadios from '@/components/SelectRadios';
import {
  POSITION_OPTIONS,
  SCENE_NUM_OPTIONS,
  ROUND_RESULT_OPTIONS,
  HU_METHOD_OPTIONS,
  MULTIPLE_OPTIONS,
  SIGN_NUM_OPTIONS,
  COURT_NUM_OPTIONS,
} from '@/configs/options.config';
import classes from './index.module.css';
import BlockButton from '@/components/BlockButton';
import SelectCheckboxes from '@/components/SelectCheckboxes';
import { cloneDeep, xor } from 'lodash';
import { useSetState } from 'ahooks';
import { HU_METHOD, ROUND_RESULT } from '@/configs/game.config';
import {
  getHostAveragePointNum,
  getGuestAveragePointNums,
  getTriggerPointNum,
} from '@/funcs/points';
import TabHeader from '@/components/TabHeader';

export default function Round() {
  const [searchParams] = useSearchParams();
  const navigate = useNavigate();
  const { gameStore, messageStore, personStore } = useContext(AppContext);
  const {
    getRoundInfoById,
    createRoundInfo,
    pushRoundInfo,
    getPositionPersonIds,
    saveRoundInfo,
  } = gameStore;
  const { getPersonsByIds } = personStore;
  const [roundInfo, setRoundInfo] = useSetState<RoundInfo>(createRoundInfo());
  const roundId = useMemo(() => searchParams.get('roundId'), [searchParams]);

  useMount(() => {
    if (roundId) {
      const findRound = getRoundInfoById(roundId);
      if (findRound) {
        setRoundInfo(cloneDeep(findRound));
      }
    }
  });

  const posisionPersonIds = useMemo(
    () => getPositionPersonIds(),
    [getPositionPersonIds],
  );

  const positionPersons = useMemo(
    () => getPersonsByIds(posisionPersonIds),
    [posisionPersonIds, getPersonsByIds],
  );

  const personOptions = useMemo(
    () =>
      positionPersons.map(p => ({
        label: p!.name,
        value: p!.id,
        key: p!.id,
      })),
    [positionPersons],
  );

  const validateRoundInfo = useCallback(
    function (roundInfo: RoundInfo) {
      const {
        scene,
        sceneNum,
        courtNum,
        roundResult,
        huMethod,
        huPersonId,
        triggerPersonId,
        multiple,
        signNum,
        reachPersonIds,
        tingPersonIds,
      } = roundInfo;
      if (scene === undefined) {
        messageStore.warning('请选择场风');
        return false;
      }
      if (sceneNum === undefined) {
        messageStore.warning('请选择局数');
        return false;
      }
      if (courtNum === undefined) {
        messageStore.warning('请选择本场');
        return false;
      }
      if (roundResult === undefined) {
        messageStore.warning('请选择结局');
        return false;
      }
      if (roundResult === ROUND_RESULT.HU) {
        if (!huPersonId) {
          messageStore.warning('请选择谁胡了');
          return false;
        }
        if (huMethod === undefined) {
          messageStore.warning('请选择胡牌方式');
          return false;
        }
        if (huMethod === HU_METHOD.RONG && !triggerPersonId) {
          messageStore.warning('请选择谁点了');
          return false;
        }
        if (huMethod === HU_METHOD.RONG && triggerPersonId === huPersonId) {
          messageStore.warning('胡牌人与点炮人不能是同一个');
          return false;
        }
        if (multiple === undefined) {
          messageStore.warning('请选择翻数');
          return false;
        }
        if (signNum === undefined) {
          messageStore.warning('请选择符数');
          return false;
        }
      } else {
        // 流程时听牌人员中要包含立直人员
        // 当有立直人员不在听牌人员中时，说明立直人员未被设置为听牌人员
        if (reachPersonIds.some(reachId => !tingPersonIds.includes(reachId))) {
          messageStore.warning('流程时听牌人员中要包含立直人员');
          return;
        }
      }
      return true;
    },
    [messageStore],
  );

  /**
   * 获取立直带来的点数变化
   * 包括胡牌后将点数给胡牌的人
   */
  const getReachChangePoints = useCallback(() => {
    const { reachPersonIds, huPersonId } = roundInfo;
    const changePoints: number[] = [];
    // 该局残余供托
    changePoints[0] = reachPersonIds.length * 1000;
    positionPersons.forEach((person, index) => {
      if (!person) return;
      changePoints[index + 1] = reachPersonIds.includes(person?.id) ? -1000 : 0;
      if (person.id === huPersonId) {
        changePoints[index + 1] += changePoints[0];
        changePoints[0] = 0;
      }
    });
    return changePoints;
  }, [roundInfo, positionPersons]);

  /**
   * 获取因流局而造成的点数变化
   */
  const getNoHuChangePoints = useCallback(() => {
    const changePoints: number[] = [];
    const { tingPersonIds, roundResult } = roundInfo;
    if (roundResult === ROUND_RESULT.NO_HU) {
      // 获取未听牌人应付罚俸值
      const punishmentPaied = [0, -1000, -1500, -3000, 0][tingPersonIds.length];
      // 获取听牌人应收罚俸值
      const punishmentGet = [0, 3000, 1500, 1000, 0][tingPersonIds.length];
      // 遍历所有人的信息
      for (let index = 1; index <= positionPersons.length; index++) {
        const positionPerson = positionPersons[index - 1];
        if (!positionPerson) continue;
        // 判断该人是听牌还是不听牌
        if (tingPersonIds.includes(positionPerson.id)) {
          changePoints[index] = punishmentGet;
        } else {
          changePoints[index] = punishmentPaied;
        }
      }
    }
    return changePoints;
  }, [positionPersons, roundInfo]);

  /** 获取点数变动 */
  const getHuChangePoints = useCallback(() => {
    const {
      roundResult,
      huMethod,
      signNum,
      multiple,
      huPersonId,
      sceneNum,
      triggerPersonId,
      courtNum,
    } = roundInfo;
    const changePoints: number[] = [];
    if (roundResult === ROUND_RESULT.HU && multiple !== undefined && signNum) {
      changePoints[0] = 0;
      // 计算胡牌的人是否为亲家
      const isHuHost = posisionPersonIds.indexOf(huPersonId) + 1 === sceneNum;
      if (huMethod === HU_METHOD.RONG) {
        // 获取放铳应付点数
        const triggerPointNum = getTriggerPointNum(
          multiple,
          signNum,
          isHuHost,
          courtNum,
        );
        // 遍历所有人员
        for (let index = 1; index <= positionPersons.length; index++) {
          const positionPerson = positionPersons[index - 1];
          if (!positionPerson) continue;
          if (positionPerson.id === huPersonId) {
            // 给胡牌的人加上应当点数
            changePoints[index] = triggerPointNum;
          } else if (positionPerson.id === triggerPersonId) {
            // 给放铳的人减去相应点数
            changePoints[index] = 0 - triggerPointNum;
          } else {
            // 其余人没有点数变化
            changePoints[index] = 0;
          }
        }
      } else if (huMethod === HU_METHOD.ZIMO) {
        // 自摸时要先分亲家自摸还是子家自摸，因为点数计算不同
        if (isHuHost) {
          const averagePointNum = getHostAveragePointNum(
            multiple,
            signNum,
            courtNum,
          );
          // 遍历所有人员
          for (let index = 1; index <= positionPersons.length; index++) {
            const positionPerson = positionPersons[index - 1];
            if (!positionPerson) continue;
            if (positionPerson.id === huPersonId) {
              // 给胡牌的人加上应当点数
              changePoints[index] = averagePointNum * 3;
            } else {
              // 其余人均减去要付的点数
              changePoints[index] = 0 - averagePointNum;
            }
          }
        } else {
          const [hostPayPointNum, guestPayPointNum] = getGuestAveragePointNums(
            multiple,
            signNum,
            courtNum,
          );
          // 遍历所有人员
          for (let index = 1; index <= positionPersons.length; index++) {
            const positionPerson = positionPersons[index - 1];
            if (!positionPerson) continue;
            if (positionPerson.id === huPersonId) {
              // 给胡牌的人加上应当点数
              changePoints[index] = hostPayPointNum + guestPayPointNum * 2;
            } else if (index === sceneNum) {
              // 亲家要付亲家的点数
              changePoints[index] = 0 - hostPayPointNum;
            } else {
              changePoints[index] = 0 - guestPayPointNum;
            }
          }
        }
      }
    }
    return changePoints;
  }, [roundInfo, positionPersons, posisionPersonIds]);

  const getTotalChangePoints = useCallback(() => {
    const changePoints: number[] = [];
    const reachChangePoints = getReachChangePoints();
    const noHuChangePoints = getNoHuChangePoints();
    const huChangePoints = getHuChangePoints();
    for (let i = 0; i < 5; i++) {
      changePoints[i] =
        (reachChangePoints[i] || 0) +
        (noHuChangePoints[i] || 0) +
        (huChangePoints[i] || 0);
    }
    return changePoints;
  }, [getReachChangePoints, getNoHuChangePoints, getHuChangePoints]);

  const handleAddRoundInfo = useCallback(
    function () {
      if (validateRoundInfo(roundInfo)) {
        roundInfo.changePoints = getTotalChangePoints();
        pushRoundInfo(roundInfo);
        messageStore.success('添加成功');
        navigate(-1);
      }
    },
    [
      roundInfo,
      validateRoundInfo,
      pushRoundInfo,
      messageStore,
      navigate,
      getTotalChangePoints,
    ],
  );

  const handleEditRoundInfo = useCallback(() => {
    if (validateRoundInfo(roundInfo)) {
      roundInfo.changePoints = getTotalChangePoints();
      saveRoundInfo(roundInfo);
      console.log('roundInfo', roundInfo);
      messageStore.success('保存成功');
      navigate(-1);
    }
  }, [
    messageStore,
    navigate,
    roundInfo,
    saveRoundInfo,
    getTotalChangePoints,
    validateRoundInfo,
  ]);

  return (
    <>
      <TabHeader title={roundId ? '编辑一局' : '添加一局'} />
      <div className={classes.Round}>
        <SelectRadios
          label="场风："
          options={POSITION_OPTIONS}
          value={roundInfo.scene}
          onChange={scene => setRoundInfo({ scene })}
        />
        <SelectRadios
          label="局数："
          options={SCENE_NUM_OPTIONS}
          value={roundInfo.sceneNum}
          onChange={sceneNum => setRoundInfo({ sceneNum })}
        />
        <SelectRadios
          label="本场："
          options={COURT_NUM_OPTIONS}
          value={roundInfo.courtNum}
          onChange={courtNum => setRoundInfo({ courtNum })}
        />
        {/* 立直是流局或和局通用的 */}
        <SelectCheckboxes
          label="立直："
          options={personOptions}
          values={roundInfo.reachPersonIds}
          onChange={id =>
            setRoundInfo({
              reachPersonIds: xor(roundInfo.reachPersonIds, [id]),
            })
          }></SelectCheckboxes>
        <SelectRadios
          label="结局："
          options={ROUND_RESULT_OPTIONS}
          value={roundInfo.roundResult}
          onChange={roundResult =>
            setRoundInfo({ roundResult })
          }></SelectRadios>

        {/* 以下是和局输入内容 */}
        {roundInfo.roundResult === ROUND_RESULT.HU && (
          <>
            <SelectRadios
              label="谁胡："
              options={personOptions}
              value={roundInfo.huPersonId}
              onChange={huPersonId =>
                setRoundInfo({ huPersonId })
              }></SelectRadios>
            <SelectRadios
              label="方式："
              options={HU_METHOD_OPTIONS}
              value={roundInfo.huMethod}
              onChange={huMethod => setRoundInfo({ huMethod })}></SelectRadios>

            {/* 不是自摸的时候要选择谁放铳 */}
            {roundInfo.huMethod === HU_METHOD.RONG && (
              <SelectRadios
                label="谁点："
                options={personOptions}
                value={roundInfo.triggerPersonId}
                onChange={triggerPersonId =>
                  setRoundInfo({ triggerPersonId })
                }></SelectRadios>
            )}

            {/* 胡牌番数 */}
            <SelectRadios
              label="翻数："
              options={MULTIPLE_OPTIONS}
              value={roundInfo.multiple}
              onChange={multiple => setRoundInfo({ multiple })}></SelectRadios>
            <SelectRadios
              label="符数："
              options={SIGN_NUM_OPTIONS}
              value={roundInfo.signNum}
              onChange={signNum => setRoundInfo({ signNum })}></SelectRadios>
          </>
        )}

        {/* 以下是流局时要考虑的 */}
        {roundInfo.roundResult === ROUND_RESULT.NO_HU && (
          <>
            <SelectCheckboxes
              label="听牌："
              options={personOptions}
              values={roundInfo.tingPersonIds}
              onChange={id =>
                setRoundInfo({
                  tingPersonIds: xor(roundInfo.tingPersonIds, [id]),
                })
              }></SelectCheckboxes>
          </>
        )}

        <div className={classes.Footer}>
          {!roundId && (
            <BlockButton
              type="primary"
              text="确认添加"
              onClick={handleAddRoundInfo}
            />
          )}
          {!!roundId && (
            <BlockButton
              type="primary"
              text="编辑保存"
              onClick={handleEditRoundInfo}
            />
          )}
        </div>
      </div>
    </>
  );
}
